<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Canvas Text Rendering Character by Character</title>
    <style>
        canvas {
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="800" height="300"></canvas>
    <script>
       document.addEventListener("DOMContentLoaded", function() {
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const textData = {
            text: "您好中国！",
            styles: [
                { start: 0, end: 2, font: "30px 黑体", color: "red" },
                { start: 2, end: 6, font: "45px 楷体", color: "green" }
            ]
        };
        let isSelecting = false;
        let selectionStart = null;
        let selectionEnd = null;
        const charWidths = [];
        let lineHeight = 0; // 添加行高变量

       function renderText() {
                let cursorX = 0;
                const cursorY = 100; // Y坐标位置
                ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除之前的渲染

                // 遍历文本之前计算选中文本的最大字体高度
                let maxHeight = 0; 
                if (selectionStart !== null && selectionEnd !== null) {
                    for (let i = selectionStart; i < selectionEnd; i++) {
                        const style = textData.styles.find(s => i >= s.start && i < s.end) || {font: "16px Arial"};
                        const fontSize = parseInt(style.font, 10); // 解析字体大小
                        maxHeight = Math.max(maxHeight, fontSize);
                    }
                    highlightSelection(cursorY - maxHeight, maxHeight + 10); // 调整矩形框高度
                }

                for (let i = 0; i < textData.text.length; i++) {
                    const char = textData.text[i];
                    const style = textData.styles.find(s => i >= s.start && i < s.end) || {font: "16px Arial", color: "black"};
                    ctx.font = style.font;
                    ctx.fillStyle = style.color;

                    const metrics = ctx.measureText(char);
                    ctx.fillText(char, cursorX, cursorY);
                    charWidths[i] = { width: metrics.width, x: cursorX };
                    cursorX += metrics.width;
                }
            }

        function highlightSelection(cursorY, lineHeight) {
            if (selectionStart === null || selectionEnd === null) return;
            const start = charWidths[selectionStart] ? charWidths[selectionStart].x : 0;
            const end = charWidths[selectionEnd - 1] ? charWidths[selectionEnd - 1].x + charWidths[selectionEnd - 1].width : start;
            
            ctx.fillStyle = 'rgba(173, 216, 230, 0.5)'; // 浅蓝色半透明
            ctx.fillRect(start, cursorY, end - start, lineHeight); // 绘制矩形高亮选中区域
        }

        function getCharIndex(x) {
            for (let i = 0; i < charWidths.length; i++) {
                const { width, x: charX } = charWidths[i];
                if (x >= charX && x <= charX + width) {
                    return i;
                }
            }
            return null;
        }

        canvas.addEventListener('mousedown', function(e) {
                const rect = canvas.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const charIndex = getCharIndex(x);

                if (charIndex !== null) {
                    isSelecting = true;
                    selectionStart = charIndex;
                    selectionEnd = charIndex + 1;
                } else {
                    selectionStart = null;
                    selectionEnd = null;
                    isSelecting = false;
                }
                renderText(); // 重新渲染更新画布状态
            });


        canvas.addEventListener('mousemove', function(e) {
            if (isSelecting) {
                const rect = canvas.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const charIndex = getCharIndex(x);
                if (charIndex !== null) {
                    selectionEnd = charIndex + 1;
                    renderText(); // 重新渲染以更新选中效果
                }
            }
        });

        canvas.addEventListener('mouseup', function(e) {
            isSelecting = false;
        });

        renderText();
    });



    </script>
</body>
</html>
